package top.lshaci.learning.springboot.web.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.util.UrlPathHelper;
import top.lshaci.learning.springboot.web.converter.GuiguConverter;

import java.util.HashMap;
import java.util.List;

/**
 * MvcConfig
 *
 * @author lshaci
 * @since 1.0.0
 */
@Configuration(proxyBeanMethods = false)
public class MvcConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    }

    /**
     * 自定义内容协商策略
     */
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        HashMap<String, MediaType> mediaTypes = new HashMap<>();
        mediaTypes.put("xml", MediaType.parseMediaType("application/xml"));
        mediaTypes.put("json", MediaType.parseMediaType("application/json"));
        mediaTypes.put("guigu", MediaType.parseMediaType("application/x-guigu"));
//        ParameterContentNegotiationStrategy parameterContentNegotiationStrategy = new ParameterContentNegotiationStrategy(mediaTypes);
//        configurer.strategies(Arrays.asList(parameterContentNegotiationStrategy, new HeaderContentNegotiationStrategy()));

        configurer.favorParameter(true);
        configurer.parameterName("format"); // http://localhost:8080/resp/person?format=guigu
        configurer.mediaTypes(mediaTypes);

        // configurer.buildContentNegotiationManager --> ContentNegotiationManagerFactoryBean.build
//        protected ContentNegotiationManager buildContentNegotiationManager() {
//            this.factory.addMediaTypes(this.mediaTypes); // 将 configurer 中定义的 mediaTypes 设置到 factory 中
//            return this.factory.build();
//        }
        // ContentNegotiationManagerFactoryBean.build [330] --> 因为在 configurer 中没有设置 strategies 所以执行 else 代码块
        // ContentNegotiationManagerFactoryBean.build [348] --> favorParameter 为 ture，所以 new ParameterContentNegotiationStrategy(this.mediaTypes);
        // ContentNegotiationManagerFactoryBean.build [359] --> !this.ignoreAcceptHeader 为 ture，所以 strategies.add(new HeaderContentNegotiationStrategy());
        // 所以最后生成的 ContentNegotiationManager 中有 ParameterContentNegotiationStrategy 和 HeaderContentNegotiationStrategy；
    }

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new GuiguConverter());
    }

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        urlPathHelper.setRemoveSemicolonContent(false);
//        urlPathHelper.setAlwaysUseFullPath(true);
        configurer.setUrlPathHelper(urlPathHelper);
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new LoginUserMethodArgumentResolver());
    }

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new String2PetConverter());
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 访问 /aa/** 所以请求都去 classpath:/static/ 下进行匹配
        registry.addResourceHandler("/aa/**")
                .addResourceLocations("classpath:/static/");
    }
}
